﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Lucene.Net.Search;
using Lucene.Net.Util;

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace iTool.Cloud.DataSearch
{
    class BytesRefOptions
    {
        public string ByteOfString { get; set; }
        public int Offset { get; set; }
        public int Length { get; set; }
    }
    public class SearchScoreDocItemOptions
    {
        public SearchScoreDocItemOptions() { }
        public SearchScoreDocItemOptions(string json)
        {
            this.LoadValues(json);
        }
        public SearchScoreDocItemOptions(FieldDoc fieldDoc)
        {
            this.Doc = fieldDoc.Doc;
            this.Score = fieldDoc.Score;
            if (fieldDoc.Fields.Any())
            {
                this.Fields = fieldDoc.Fields;
                this.FieldTypes = fieldDoc.Fields.Select(item => item.GetType().FullName).ToArray();
            }
            this.ShardIndex = fieldDoc.ShardIndex;
        }
        public int Doc { get; set; }
        public float Score { get; set; }
        public object[] Fields { get; set; }
        public string[] FieldTypes { get; set; }
        public int ShardIndex { get; set; }

        public override string ToString()
        {
            for (int i = 0; i < this.Fields.Length; i++)
            {
                switch (this.FieldTypes[i])
                {
                    case "Lucene.Net.Util.BytesRef":
                        var bytesRef = (Lucene.Net.Util.BytesRef)this.Fields[i];
                        this.Fields[i] = new BytesRefOptions
                        {
                            ByteOfString = Encoding.Default.GetString(bytesRef.Bytes),
                            Length = bytesRef.Length,
                            Offset = bytesRef.Offset
                        };
                        break;
                }
            }
            string json = JsonConvert.SerializeObject(this);
            byte[] b = Encoding.Default.GetBytes(json);
            return Convert.ToBase64String(b);
            //return JsonConvert.SerializeObject(this);
        }

        public void LoadValues(string json)
        {
            if (string.IsNullOrWhiteSpace(json))
            {
                return;
            }

            byte[] b = Convert.FromBase64String(json);
            json = System.Text.Encoding.Default.GetString(b);
            if (string.IsNullOrWhiteSpace(json))
            {
                return;
            }
            var scoreDoc = Newtonsoft.Json.JsonConvert.DeserializeObject<SearchScoreDocItemOptions>(json);
            if (scoreDoc != null)
            {
                this.Doc = scoreDoc.Doc;
                this.Score = scoreDoc.Score;
                this.Fields = scoreDoc.Fields;
                this.FieldTypes = scoreDoc.FieldTypes;

                for (int i = 0; i < this.Fields.Length; i++)
                {
                    switch (this.FieldTypes[i])
                    {
                        case "Lucene.Net.Util.BytesRef":
                            var entity = (JObject)this.Fields[i];
                            this.Fields[i] = new BytesRefOptions
                            {
                                Length = (int)entity["Length"],
                                Offset = (int)entity["Offset"],
                                ByteOfString = entity["ByteOfString"].ToString(),
                            };
                            break;
                        case "J2N.Numerics.Single":
                        case "J2N.Numerics.Double":
                        case "J2N.Numerics.Int32":
                        case "J2N.Numerics.Int16":
                        case "J2N.Numerics.Int64":
                            this.Fields = scoreDoc.Fields;
                            break;
                    }
                }

                    
                this.ShardIndex = scoreDoc.ShardIndex;
            }
        }


        public FieldDoc? GetFieldDocItem()
        {
            if (this.FieldTypes == default)
            {
                return default;
            }

            object[] Fields = new object[this.Fields.Count()];
            for (int i = 0; i < this.Fields.Length; i++)
            {
                switch (this.FieldTypes[i])
                {
                    case "Lucene.Net.Util.BytesRef":
                        var options = (BytesRefOptions)this.Fields[i];
                        Fields[i] = new Lucene.Net.Util.BytesRef(Encoding.Default.GetBytes(options.ByteOfString), options.Offset, options.Length);
                        break;
                    case "J2N.Numerics.Double":
                        Fields[i] = J2N.Numerics.Double.GetInstance((double)this.Fields[i]);
                        break;
                    case "J2N.Numerics.Single":
                        Fields[i] = J2N.Numerics.Single.GetInstance(float.Parse(this.Fields[i].ToString()));
                        break;
                    case "J2N.Numerics.Int32":
                        Fields[i] = J2N.Numerics.Int32.GetInstance(int.Parse(this.Fields[i].ToString()));
                        break;
                    case "J2N.Numerics.Int16":
                        Fields[i] = J2N.Numerics.Int16.GetInstance(short.Parse(this.Fields[i].ToString()));
                        break;
                    case "J2N.Numerics.Int64":
                        Fields[i] = J2N.Numerics.Int64.GetInstance(long.Parse(this.Fields[i].ToString()));
                        break;
                }
            }

            return new FieldDoc(this.Doc, this.Score, Fields, this.ShardIndex);
        }
    }
}
